<?php
/**
 * Created by JetBrains PhpStorm.
 * User: Max
 * Date: 01.02.11
 * Time: 15:27
 * To change this template use File | Settings | File Templates.
 */

class Rent_Reader_Premier
{
    const PATTERN_SECTION = '/rub=([0-9]{1,4})/';

    /**
     * Page name in URL
     *
     * @var string
     */
    protected $_pageName = 'page';

    /**
     * Main link
     *
     * @var string
     */
    protected $_url;

    /**
     * Columns html ids
     * @var array
     */
    protected $_htmlColIds = array(
        'ctl00_CentralPlaceHolder_LookObjavaControl_Coll1Panel' ,
        'ctl00_CentralPlaceHolder_LookObjavaControl_Coll2Panel' ,
    );

    /**
     * Links block html id
     * @var string
     */
    protected $_htmlLinksId = 'ctl00_CentralPlaceHolder_LookObjavaControl_PagePrinter';

    /**
     * Html dom object
     *
     * @var simple_html_dom
     */
    protected $_html;

    /**
     * Page for load
     *
     * @var int
     */
    protected $_page = 0;

    /**
     * Total pages
     *
     * @var int
     */
    protected $_totalPages;

    /**
     * Adverts
     *
     * @var array
     */
    protected $_adverts = array();

    /**
     * Phones
     *
     * @var array
     */
    protected $_phones = array();

    /**
     * Hash key load
     *
     * Used for reload ads and save archive
     *
     * @var
     */
    protected $_loadKey;

    /**
     * Path to archive files
     *
     * @var string
     */
    protected $_archivePath;

    /**
     * Hash name
     *
     * @var string
     */
    protected $_hashNameFormat;

    /**
     * Section id
     *
     * @var string
     */
    protected $_sectionId;

    /**
     * Max length in gotten for the getting hash of advert
     *
     * @var int
     */
    protected $_hashTextLength = 100;

    /**
     * Max length in gotten for the getting hash of advert
     *
     * @var int
     */
    protected $_currentDate;

    /**
     * Set main url
     *
     * @param string $url
     * @return Rent_Reader_Premier
     */
    public function setUrl($url)
    {
        if ($url != $this->_url) {
            $this->_url = (string) $url;
            $this->_page = null;
            $this->_html = null;
            $this->_totalPages = null;
            $this->_loadKey = null;
            $this->_adverts = array();
        }
        return $this;
    }

    /**
     * Set path to archive
     *
     * @param string $path
     * @return Rent_Reader_Premier
     */
    public function setArchivePath($path)
    {
        $path = rtrim($path, '/\\');
        $this->_archivePath = $path . DIRECTORY_SEPARATOR;
        return $this;
    }

    /**
     * Get path to archive
     *
     * @return string
     */
    public function getArchivePath()
    {
        return $this->_archivePath;
    }

    /**
     * Get html dom
     *
     * @return simple_html_dom
     */
    protected function _getContent()
    {
        if ($this->_page && $this->getTotalPages() >= $this->_page) {
            $url = $this->_url . "&$this->_pageName=" . $this->_page;
            $this->_html = file_get_html($url);
        } else {
            $this->_html = file_get_html($this->_url);
            $menuText = $this->_html->find('.col-collateral > .r-menu-border', 0)
                    ->find('.section-nav', 0)
                    ->find('.on a', 0)
            ;
            if (false === strpos($menuText, $this->getCurrentDate())) {
                throw new Rent_Reader_Exception('Requested date and date of creating page do not match');
            }
        }
        return $this->_html;
    }

    /**
     * Get total pages count
     *
     * @return int
     */
    public function getTotalPages()
    {
        if (null === $this->_totalPages) {
            $links = $this->_html->getElementById($this->_htmlLinksId);
            $this->_totalPages = count($links->children);
        }
        return $this->_totalPages;
    }

    /**
     * Get hash name
     *
     * @return string
     */
    public function getHashName()
    {
        return sprintf($this->_hashNameFormat, $this->getSectionId());
    }

    /**
     * Set hash name
     *
     * @return string
     */
    public function setHashNameFormat($name)
    {
        return $this->_hashNameFormat = (string) $name;
    }

    /**
     * Get section id
     *
     * @return string
     */
    public function getSectionUrlId()
    {
        preg_match(self::PATTERN_SECTION, $this->_url, $matches);
        if ($matches) {
            return $matches[1];
        }
    }

    /**
     * Get section id
     *
     * @return string
     */
    public function getSectionId()
    {
        return $this->_sectionId;
    }

    /**
     * Set section id
     *
     * @param string $id
     * @return void
     */
    public function setSectionId($id)
    {
        $this->_sectionId = (string) $id;
    }

    /**
     * Get ads from all pages
     *
     * @return array
     */
    public function getAds()
    {
        if (!$this->_adverts && !$this->hasArchive()) {
            $this->_loadKey = $this->getHashName();

            if (null === $this->_html) {
                $this->_getContent();
            }

            $this->_adverts = array();
            if ($this->getTotalPages() > 0) {
                for ($this->_page = 1; $this->getTotalPages() >= $this->_page; $this->_page++) {
                    foreach ($this->_htmlColIds as $colId) {
                        $colWithAdverts = $this->_html->getElementById($colId);
                        /** @var $node simple_html_dom_node */
                        foreach ($colWithAdverts->children as $node) {
                            $text = $node->innertext();
                            $phones = $this->_getPhones($text);
                            if ($phones) {
                                $hash = md5(mb_substr($text, 0, $this->_hashTextLength, 'utf-8'));

                                //skip advert if it almost the same
                                if (!empty($this->_adverts[$hash])) {
                                    continue;
                                }

                                $this->_adverts[$hash] = array(
                                    'content' => $text ,
                                    'phones'  => $phones ,
                                    'page'    => $this->_page ,
                                    'hash'    => $hash,
                                );
                                foreach ($phones as $phone) {
                                    //check invalid phone. Phone cannot be less format XX-XX-XX

                                    if ($phone < 100000) {
                                        throw new Rent_Reader_Exception('Invalid phone number');
                                    }
                                    if (empty($this->_phones[$phone])) {
                                        $this->_phones[$phone] = 1;
                                    } else {
                                        $this->_phones[$phone]++;
                                    }
                                }
                            }
                        }
                    }
                    if ($this->getTotalPages() != $this->_page) {
                        $this->_getContent();
                    }
                }
            }
        } elseif (!$this->_adverts) {
            $this->_adverts = require_once $this->getArchiveFile();
            //add phones
            foreach ($this->_adverts as $item) {
                foreach ($item['phones'] as $phone) {
                    if (empty($this->_phones[$phone])) {
                        $this->_phones[$phone] = 1;
                    } else {
                        $this->_phones[$phone]++;
                    }
                }
            }
        }
        return $this->_adverts;
    }

    /**
     * Save adverts to archive
     *
     * @return Rent_Reader_Premier
     */
    public function saveToArchive()
    {
        if ($this->_adverts) {
            //get code
            ob_start();
            var_export($this->_adverts);
            $code = ob_get_contents();
            ob_end_clean();

            //write to file
            $file = $this->getArchiveFile();
            $info = pathinfo($file);
            if (!file_exists($info['dirname'])) {
                if (!mkdir($info['dirname'])) {
                    throw new Rent_Exception('Cannot make archive dir');
                }
            }
            $fh = fopen($file, 'w') or due('Can not open file');

            $warning = 'PLEASE DO NOT CHANGE THIS FILE';
            if (!fwrite($fh, "<?php" . PHP_EOL . "/*$warning*/" . PHP_EOL . " return $code ;")) {
                throw new Rent_Exception('Can not create archive file');
            }
            fclose($fh);
        }
        return $this;
    }

    /**
     * Get all found phones
     * @return array
     */
    public function getPhones()
    {
        return $this->_phones;
    }

    /**
     * Request has archive?
     *
     * @return bool
     */
    public function hasArchive()
    {
        return file_exists($this->getArchiveFile());
    }

    /**
     * Get path to archive file
     *
     * @return string
     */
    public function getArchiveFile()
    {
        return $this->_archivePath . $this->getHashName() . '.php';
    }

    /**
     * Get phones from ad
     *
     * @param string $str
     * @return array
     */
    protected function _getPhones($str)
    {
        $matches = null;
        $mobileCodes = '68|39|63|93|50|95|66|94|98|97|67|96|92|91|99';
        $reg = '(\s0(' . $mobileCodes . ')[\-\s]?[0-9]{3}[\-\s]?[0-9]{2}[\-\s]?[0-9]{2})|'
             . '(\s0(' . $mobileCodes . ')[\-\s]?[0-9]{2}[\-\s]?[0-9]{3}[\-\s]?[0-9]{2})|'
             . '(\s0(' . $mobileCodes . ')[\-\s]?[0-9]{2}[\-\s]?[0-9]{2}[\-\s]?[0-9]{3})|'
             . '(\s[1-9][0-9]{2}[\-\s]?[0-9]{1}[\-\s]?[0-9]{3})|'
             . '(\s[1-9][0-9]{1,2}[\-\s]?[0-9]{2}[\-\s]?[0-9]{2})';
        preg_match_all('/' . $reg . '/', $str, $matches);
        $phones = array();
        if ($matches) {
            foreach ($matches[0] as $phone) {
                $phone = str_replace(' ', '', $phone);
                $phones[] = str_replace('-', '', $phone);
            }
        }
        return $phones;
    }

    /**
     * Get current date
     *
     * @param string $date
     * @return Rent_Reader_Premier
     */
    public function setCurrentDate($date)
    {
        /**
         * Filter
         */
        $matches = array();
        preg_match('/([0-9]{2})-([0-9]{2})-([0-9]{2})/', $date, $matches);
        unset($matches[0]);

        if (count($matches) != 3) {
            throw new Rent_Reader_Exception('Invalid current date');
        }

        $this->_currentDate = implode('.', array_reverse($matches));
        return $this;
    }

    /**
     * Get current date
     *
     * @return string
     */
    public function getCurrentDate()
    {
        if (null === $this->_currentDate) {
            throw new Rent_Reader_Exception('Current date cannot be null');
        }
        return $this->_currentDate;
    }
}

